//@author A0005591J
#include"Search.h"

Search::Search()
{
}

void Search::SearchFile(string file)
{
	filename = file;
}
double Search::Day_total_CF(string Date, Item& thisItem)
{
		addressList.clear();
	    double totalCF=0;
		streampos address;
		ifstream infile (filename.c_str());//note that end of file XXX.txt should not include \n
		infile.seekg(-1,ios::end);// if end with a space must put "-1"
		streampos endpos = infile.tellg();
		infile.seekg(ios::beg);

		while(infile.tellg() < endpos)
		{	
			address = infile.tellg();
			thisItem. record_from_file(infile, address);
			if(Date == thisItem. getDate()) {
				totalCF += thisItem. getPrice();
				addressList.push_back(address);
			}
		}
		return totalCF;
}
double Search::Month_total_CF(int y, int m ,Item& thisItem)
{
	double amt=0;//the total amt in this month
	string EndDay,StartDay;
	
	ostringstream out;

	out << y * 10000 + m * 100 + 1;
	StartDay = out.str();

	ostringstream outend;
	outend << y * 10000 + m * 100 + 31;
	EndDay = outend.str();

	streampos address;

	ifstream infile (filename.c_str());//note that end of file XXX.txt should not include \n
	infile.seekg(-1,ios::end);// if end with a space must put "-1"
	streampos endpos = infile.tellg();
	infile.seekg(ios::beg);
	
	while(infile.tellg()<endpos)	
	{
		address = infile.tellg();
		thisItem. record_from_file(infile, address);
		if(thisItem. getDate() <= EndDay && thisItem. getDate() >= StartDay)
			amt += thisItem. getPrice();
	}
	return amt;
}

void Search::SearchKeyword(string key, Item& tempItem)
{
	    key=convert_lower(key);
	    addressList.clear();//clear the search result last time

		streampos address;
		ifstream infile (filename.c_str());//note that end of file Data.txt should not include \n
		infile.seekg(-1,ios::end);
		streampos endpos = infile.tellg();
		infile.seekg(ios::beg);
		
		while(infile.tellg()<endpos)
			{
			address = infile.tellg();
			tempItem.record_from_file(infile, address);
	        //need to make sure that all the strings are in lower case or upper case- change the getters in ItemSpec
			if((convert_lower(tempItem.getName()).find(key)!=string::npos)||(convert_lower(tempItem.getVenue()).find(key)!=string::npos)||(convert_lower(tempItem.getCategory()).find(key)!=string::npos) || (convert_lower(tempItem.getPayer()).find(key)!=string::npos))
				addressList.push_back(address);
			}
}
streampos Search::internalSearch (Item &thisItem, Item& emptyItem)
{
	
		ifstream infile (filename.c_str());
		streampos address;//need parameter address only for internal search in fact
		infile.seekg(-1,ios::end);
		streampos endpos = infile.tellg();
		infile.seekg(ios::beg);
		
		while(infile.tellg() < endpos)
		{
			address = infile.tellg();
			emptyItem. record_from_file(infile, address);
			if(emptyItem. compare(thisItem))
				return address;
		}

		return infile.tellg();//if not found, return the end position of this file.
}
bool Search::powerSearch()
{
	addressList.clear();
	ifstream infile;
	infile.open(filename.c_str());
	infile.seekg(-1,ios::end);
	streampos end=infile.tellg();
	infile.seekg(ios::beg);
	streampos address;
	int choice;
	double minp=-1,maxp=-1;//boundary for the price,-1 indicate no boundary
	string mindate="",maxdate="";//boundary for the date,""indicate no boundary
	SearchSpec nameSpec;
	SearchSpec cateSpec;
	SearchSpec payerSpec;
	SearchSpec venueSpec;
	cout<<"Please input information for advanced search on your Expense/Payment"<<endl;
	cout<<" 1 for Nameinfo\n 2 for Priceinfo\n 3 for Dateinfo\n 4 for categpryInfo\n 5 for VenueInfo\n 6 for PayerInfo\n 7 for Enter"<<endl;
	cout<<"Input your choice: ";
	cin>>choice;
	while(choice!=7)
	{
	switch(choice)
	{
	        case 1:cout<<"Please input info on Name of the Item"<<endl;
				nameSpec.read_in();
		    break;
			case 2: cout<<"Please input lower and upper boundary of price"<<endl;
				    cin>>minp>>maxp;
		    break;
			case 3: cout<<"Please input lower and upper boundary of Date"<<endl;
				    cin>>mindate>>maxdate;
		    break;
			case 4: cout<<"Please input info on category of the Item"<<endl;
				cateSpec.read_in();
		    break;
			case 5: cout<<"Please input info on venue of the Item"<<endl;
				venueSpec.read_in();
		    break;
			case 6: cout<<"Please input info on payer of the Item"<<endl;
				payerSpec.read_in();
		    break;
			case 7:
			break;
	}
	cout<<"Input your choice: ";
	cin>>choice;
	}
	if(filename=="Payment.txt")//if filename diff, declare diff Item type
	{
	PaymentItem *temp= new PaymentItem;
	while(infile.tellg()<end)
	{
		address=infile.tellg();
		temp->record_from_file(infile,address);
		if(nameSpec.is_empty()||nameSpec.match(convert_lower(temp->getName())))
			if(minp==-1||(temp->getPrice()>=minp&&temp->getPrice()<=maxp))
				if(cateSpec.is_empty()||cateSpec.match(convert_lower(temp->getCategory())))
					if(mindate==""||(temp->getDate()>=mindate&&temp->getDate()<=maxdate))
						if(payerSpec.is_empty()||payerSpec.match(convert_lower(temp->getPayer())))
						addressList.push_back(address);
	}

	}
	else
	{
		XpensItem *temp=new XpensItem;
			while(infile.tellg()<end)
	{
		address=infile.tellg();
		temp->record_from_file(infile,address);
		if(nameSpec.is_empty()||nameSpec.match(convert_lower(temp->getName())))
			if(minp==-1||(temp->getPrice()>=minp&&temp->getPrice()<=maxp))
				if(cateSpec.is_empty()||cateSpec.match(convert_lower(temp->getCategory())))
					if(mindate==""||(temp->getDate()>=mindate&&temp->getDate()<=maxdate))
						if(venueSpec.is_empty()||venueSpec.match(convert_lower(temp->getVenue())))
						addressList.push_back(address);
	}
	}
	if(addressList.empty())
		return false;
	return true;
}

bool Search::Print(Item& temp)
{
		if(addressList.empty())
	{
		cout<<"Not found"<<endl;
	   return false;
	}
	ifstream infile (filename.c_str(),ios::in|ios::ate);
	cout << "ID  |Name                            |Price     \n";
	cout << "    |Category            |Date       |";
	
	if (temp.isexpense()) cout << "Venue                         \n";
	else cout << "Payer                         \n";
	cout << "-------------------------------------------------------------------------------\n";
	
	for(int i = 0;i < addressList.size();i ++)
	{	
		temp. record_from_file(infile, addressList[i]);
		cout << std::left << setw(4);
		cout << i+1 ;
		temp. print();
	}

	return true;
}

streampos Search::getAddress(int pos)
{ 
	return addressList[pos];
}


void Search::getItem(int pos, Item& thisItem)
{
	ifstream infile(filename.c_str());
	thisItem. record_from_file( infile, addressList[pos] );
}

int Search::numOfItems(){
	return addressList.size();
}

string Search:: convert_lower(string str)
{
	for(int i = 0;i < str.size();i ++)
		str[i]=tolower(str[i]);
	return str;
}